/**
 * Copyright 2010 The Regents of the University of California
 *
 *  All Rights Reserved
 */

/* DC Switch */

#include <sys/types.h>
#include <inttypes.h>
#include <netinet/in.h>
#include <stdlib.h>

#include "packet-in-handler.h"
#include "dcswitch.h"

#include "openflow/openflow.h"
#include "flow.h"
#include "ofpbuf.h"
#include "learning-switch.h"
#include "vconn.h"
#include "xtoxll.h"

#define THIS_MODULE VLM_packet_in_handler
#include "vlog.h"

void packet_in_handler(struct lswitch *sw, struct rconn *rconn, void *opi_)
{
    struct ofp_packet_in *opi = opi_;
    uint16_t in_port = ntohs(opi->in_port);
    uint16_t out_port = OFPP_FLOOD;

    size_t pkt_ofs, pkt_len;
    struct ofpbuf pkt;
    struct flow flow;

    int sw_index;
    uint64_t sw_id = sw->datapath_id;

    /* Extract flow data from 'opi' into 'flow'. */
    pkt_ofs = offsetof(struct ofp_packet_in, data);
    pkt_len = ntohs(opi->header.length) - pkt_ofs;
    pkt.data = opi->data;
    pkt.size = pkt_len;
    flow_extract(&pkt, in_port, &flow);

    sw_index = lookupSwitchIndex(sw_id);
    if (sw_index < 0) {
        VLOG_WARN("UNKOWN SWITCH REPORTING PACKET IN ! Switch ID = %"PRIx64"", sw_id);
        return;
    }

    VLOG_DBG("Incoming packet on switch with index %d, dl_type = %x", sw_index, ntohs(flow.dl_type));

    if (ntohs(flow.dl_type) == 0x0800) {
        // THIS MUST BE DONE ONLY FOR REGULAR IP PACKETS: Ensure Ethernet type 0x800
        // Pod switch? (remember! Assuming PRE-fixes already exist, therefore any traffic asking for directions is going up only)
        // Just perform a random assignment of output port (upward facing)

        if (sw_index >=0 && sw_index < 16) {
            out_port = 2 + (rand() % 2);

            queue_tx_wrapper(sw, rconn, make_add_simple_flow(&flow, ntohl(opi->buffer_id),
                                                 out_port, UNICAST_FLOW_TIMEOUT));
        }
        else if (sw_index >= 16 && sw_index <20) {
            // must be a core then, and this is *inter-pod*
	        VLOG_WARN("Why is core switch doing Packet_in request?!? nw_src = %x nw_dst = %x", ntohl(flow.nw_src), ntohl(flow.nw_dst));
            goto drop_it;
        }
    }
    else {
        goto drop_it;
    }
    return;

drop_it:
    /* Set up a flow to drop packets, or just drop the packet if we don't set
     * up flows at all. */
    if (sw->max_idle >= 0) {
        queue_tx_wrapper(sw, rconn, make_add_flow(&flow, ntohl(opi->buffer_id),
                                          sw->max_idle, 0));
    }
    return;
}

